package org.openbpm.base.autoconfiguration;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.github.pagehelper.PageInterceptor;
import com.sec.etech.common.MyBatisPlusMetaObjectHandler;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.openbpm.base.dao.baseinterceptor.QueryInterceptor;
import org.openbpm.base.dao.baseinterceptor.SaveInterceptor;
import org.openbpm.base.db.datasource.DynamicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.*;

/**
 * 数据源配置
 *
 */
@EnableConfigurationProperties({DataSourceExtraProperties.class})
@Configuration
public class DataSourceAutoConfiguration {

    @Primary
    @ConditionalOnClass(HikariDataSource.class)
    @Bean(value="dataSourceDefault", destroyMethod = "close")
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSourceDefault(DataSourceProperties dataSourceProperties) {
        return (HikariDataSource) dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean("dataSource")
    public DynamicDataSource dataSource(DataSourceExtraProperties dataSourceExtraProperties,@Autowired DataSource dataSourceDefault) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>(1);
        targetDataSources.put("dataSourceDefault", dataSourceDefault);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultDbtype(dataSourceExtraProperties.getDbType());
        return dynamicDataSource;
    }

    @Bean(name = "jdbcTemplate")
    public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource) {

        return new JdbcTemplate(dataSource);
    }

    public PageInterceptor pageInterceptor() {
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("autoRuntimeDialect", "true");
        properties.setProperty("rowBoundsWithCount", "true");
        pageInterceptor.setProperties(properties);
        return pageInterceptor;
    }
    @Bean
    public QueryInterceptor queryInterceptor() {
        return new QueryInterceptor();
    }

    @Bean
    public SaveInterceptor saveInterceptor() {
        return new SaveInterceptor();
    }

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

//    @Bean
//    public MybatisPlusInterceptor optimisticLockerInterceptor() {
//        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//        return interceptor;
//    }

    // MapperLocations TODO 可配置
    @Bean(name = "bpmSqlSessionFactory")
    public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource,SaveInterceptor saveInterceptor) {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations("classpath*:org/openbpm/*/mapping/*.xml", "classpath*:org/openbpm/*/*/mapping/*.xml", "classpath*:org/openbpm/**/mapping/*.xml"));
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{
                pageInterceptor(),
                queryInterceptor(),
                optimisticLockerInterceptor(),
                saveInterceptor
        });

        // 设置多环境的配置
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();

        Properties mysqlp = new Properties();
        mysqlp.setProperty("MySQL", "mysql");
        mysqlp.setProperty("Oracle", "oracle");
        //mysqlp.setProperty("SqlServer", "sqlserver");
        //mysqlp.setProperty("PostgreSql", "postgresql");
        databaseIdProvider.setProperties(mysqlp);

        sqlSessionFactoryBean.setDatabaseIdProvider(databaseIdProvider);

        //全局配置
        GlobalConfig globalConfig  = new GlobalConfig();
        //配置填充器
        globalConfig.setMetaObjectHandler(new MyBatisPlusMetaObjectHandler());
        sqlSessionFactoryBean.setGlobalConfig(globalConfig);

        return sqlSessionFactoryBean;
    }

    private Resource[] resolveMapperLocations(String... locations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList<>();
        for (String mapperLocation : locations) {
            try {
                Resource[] mappers = resourceResolver.getResources(mapperLocation);
                resources.addAll(Arrays.asList(mappers));
            } catch (IOException e) {
                // ignore
            }
        }
        return resources.toArray(new Resource[resources.size()]);
    }
    // DAO 层 BasePackage TODO 可配置
    @Bean("bpmMapperScannerConfigurer")
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("bpmSqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("org.openbpm.**.dao,org.openbpm.**.mapper,**.mapper");
        return mapperScannerConfigurer;
    }

    @Bean("bpmSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("bpmSqlSessionFactory") MybatisSqlSessionFactoryBean sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory.getObject());
    }
}
